#include <QDebug>
#include "decodethread.h"
#include "videoplayer.h"
#include "ffinclude.h"

DecodeThread::DecodeThread(DecodeType type,VideoPlayer *player):QThread(player)
{
    m_decodeType=type;
    m_player=player;
}

void DecodeThread::play()
{
    if(!this->isRunning()){
        m_reqPause=false;
        m_reqStop=false;
        this->start();
    }else{
        m_reqPause=false;
        m_reqStop=false;
    }
}

void DecodeThread::pause()
{
    m_reqPause=true;
    m_reqStop=false;
}

void DecodeThread::stop()
{
    m_reqPause=false;
    m_reqStop=true;
    if(m_decodeType==VideoDecode){
        frame_queue_signal(&m_player->m_playerInfo->videoFrameQueue);
    }else if(m_decodeType==AudioDecode){
        frame_queue_signal(&m_player->m_playerInfo->audioFrameQueue);
    }else if(m_decodeType==TextDecode){
        frame_queue_signal(&m_player->m_playerInfo->textFrameQueue);
    }
    this->wait();
}

void DecodeThread::run()
{
    PlayerInfo *playerInfo = m_player->m_playerInfo;

    //打开解码器
    if(!openDecoder()){
        emit error(m_lastErrorMsg);
        return;
    }

    emit inited();

    //开始解码
    AVRational tempRational={0,0};
    AVRational videoFramerate;
    if(m_decodeType==VideoDecode){
        videoFramerate=av_guess_frame_rate(playerInfo->formatContext, playerInfo->videoStream, NULL);
    }
    bool isValid=false;
    Frame* myFrame=NULL;
    AVFrame *frame = av_frame_alloc();
    for (;;) {
        if(m_reqStop){
            break;
        }
        if(m_decodeType==VideoDecode || m_decodeType==AudioDecode){
            //音视频先解码再取包和缓存
            decodeNextAVFrame(frame,&isValid);
            if(!isValid){
                continue;
            }

            if(m_decodeType==VideoDecode){
                myFrame=frame_queue_peek_writable(&m_player->m_playerInfo->videoFrameQueue);
                if(myFrame){
                    myFrame->sar = frame->sample_aspect_ratio;
                    myFrame->width = frame->width;
                    myFrame->height = frame->height;
                    myFrame->format = frame->format;
                    myFrame->pts =(frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(playerInfo->videoStream->time_base);;
                    if(videoFramerate.den!=0 && videoFramerate.num!=0){
                        tempRational.num=videoFramerate.den;
                        tempRational.den=videoFramerate.num;
                        myFrame->duration = av_q2d(tempRational);
                    }else{
                        myFrame->duration =0;
                    }
                    myFrame->pos = frame->pkt_pos;
                    myFrame->serial =  this->m_pktSerial;
                    myFrame->uploaded = 0;

                    av_frame_move_ref(myFrame->frame, frame);
                    frame_queue_push(&m_player->m_playerInfo->videoFrameQueue);
                }
               // av_frame_unref(frame);  TODO: frame没有经过传递，是否还要释放？
            }else if(m_decodeType==AudioDecode){
                myFrame = frame_queue_peek_writable(&playerInfo->audioFrameQueue);
                if(myFrame){
                    if(frame->pts == AV_NOPTS_VALUE){
                        myFrame->pts=NAN;
                    }else if(frame->sample_rate!=0){
                        tempRational.num=1;
                        tempRational.den=frame->sample_rate;
                        myFrame->pts=frame->pts * av_q2d(tempRational);
                    }else{
                        myFrame->pts=NAN;
                    }
                    myFrame->pos = frame->pkt_pos;
                    myFrame->serial = playerInfo->auddec.pkt_serial;
                    if(frame->nb_samples!=0 && frame->sample_rate!=0){
                        tempRational.num=frame->nb_samples;
                        tempRational.den=frame->sample_rate;
                        myFrame->duration = av_q2d(tempRational);
                    }else{
                        myFrame->duration = 0;
                    }

                    av_frame_move_ref(myFrame->frame, frame);
                    frame_queue_push(&playerInfo->audioFrameQueue);
                }
            }

        }else{
            //字幕先取包再解码和缓存，避免多次拷贝数据
            myFrame = frame_queue_peek_writable(&playerInfo->textFrameQueue);
            if(myFrame){
                decodeNextAVText(&myFrame->sub,&isValid);
                if(!isValid){
                    continue;
                }

                if (myFrame->sub.format == 0) {
                    if (myFrame->sub.pts != AV_NOPTS_VALUE){
                        myFrame->pts = myFrame->sub.pts / (double)AV_TIME_BASE;
                    }else{
                        myFrame->pts = 0;
                    }
                    myFrame->serial = playerInfo->subdec.pkt_serial;
                    myFrame->width = playerInfo->subdec.avctx->width;
                    myFrame->height = playerInfo->subdec.avctx->height;
                    myFrame->uploaded = 0;

                    frame_queue_push(&playerInfo->textFrameQueue);
                }else{
                    avsubtitle_free(&myFrame->sub);
                }
            }
        }
    }

    //关闭解码器
    av_frame_free(&frame);
    closeDecoder();
}

bool DecodeThread::openDecoder()
{
    PlayerInfo *playerInfo = m_player->m_playerInfo;
    PlayerConfig* playerConfig = &m_player->m_playerConfig;

    int retCode = 0;

    //初始化解码器上下文
    AVCodecContext* codecContext=NULL;
    codecContext = avcodec_alloc_context3(NULL);
    if (!codecContext){
        m_lastErrorMsg="avcodec_alloc_context3失败";
        return false;
    }

    AVStream* stream=NULL;
    if(m_decodeType==VideoDecode){
        stream=playerInfo->videoStream;
    }else if(m_decodeType==AudioDecode){
        stream=playerInfo->audioStream;
    }else if(m_decodeType==TextDecode){
        stream=playerInfo->textStream;
    }
    if(!stream){
        m_lastErrorMsg="流无效";
        return false;
    }

    retCode = avcodec_parameters_to_context(codecContext, stream->codecpar);
    if (retCode < 0){
        closeDecoder();
        m_lastErrorMsg=QString("解码器上下文初始化失败（%1）").arg(avErrorCodeToString(retCode));
        return false;
    }

    //查找解码器
    AVCodec* codec=NULL;
    QString forceCodecName;
    if(m_decodeType==VideoDecode){
        forceCodecName=playerConfig->vcodecName;
    }else if(m_decodeType==AudioDecode){
        forceCodecName=playerConfig->acodecName;
    }
    if(forceCodecName!=""){
        codec=avcodec_find_decoder_by_name(forceCodecName.toStdString().data());
    }
    if(!codec){
        codec = avcodec_find_decoder(codecContext->codec_id);
    }
    if(!codec){
        closeDecoder();
        m_lastErrorMsg="未找到合适的解码器";
        return false;
    }

    //设置解码器上下文参数
    codecContext->codec_id = codec->id;
    if(m_decodeType==VideoDecode && m_player->m_playerInfo->videoStream){
        av_codec_set_pkt_timebase(codecContext, m_player->m_playerInfo->videoStream->time_base);
    }else if(m_decodeType==AudioDecode && m_player->m_playerInfo->audioStream){
        av_codec_set_pkt_timebase(codecContext, m_player->m_playerInfo->audioStream->time_base);
    }else if(m_decodeType==TextDecode && m_player->m_playerInfo->textStream){
        av_codec_set_pkt_timebase(codecContext, m_player->m_playerInfo->textStream->time_base);
    }

    int lowers=0;
    if(playerConfig->lowers>0){
        int maxLowres = av_codec_get_max_lowres(codec);
        if(playerConfig->lowers > maxLowres){
            lowers=maxLowres;
            av_codec_set_lowres(codecContext, maxLowres);
        }else{
            lowers=playerConfig->lowers;
            av_codec_set_lowres(codecContext, playerConfig->lowers);
        }
    }

#if FF_API_EMU_EDGE
    if(playerConfig->lowers>0){
        codecContext->flags |= CODEC_FLAG_EMU_EDGE;
    }
#endif
    if (playerConfig->fastMode){
        codecContext->flags2 |= AV_CODEC_FLAG2_FAST;
    }
#if FF_API_EMU_EDGE
    if(codec->capabilities & AV_CODEC_CAP_DR1){
        codecContext->flags |= CODEC_FLAG_EMU_EDGE;
    }
#endif


    //打开解码器
    AVDictionary *opts=NULL;
    if(lowers>0){
        av_dict_set_int(&opts, "lowres", lowers, 0);
    }
    if(playerConfig->codecThreads>0){
        av_dict_set(&opts, "threads", QString::number(playerConfig->codecThreads).toStdString().data(), 0);
    }else{
        av_dict_set(&opts, "threads", "auto", 0);
    }
    if (codecContext->codec_type == AVMEDIA_TYPE_VIDEO || codecContext->codec_type == AVMEDIA_TYPE_AUDIO){
        av_dict_set(&opts, "refcounted_frames", "1", 0);
    }
    if ((retCode = avcodec_open2(codecContext, codec, &opts)) < 0) {
        closeDecoder();
        m_lastErrorMsg=QString("解码器打开失败（%1）").arg(avErrorCodeToString(retCode));
        return false;
    }

    if(m_decodeType==VideoDecode){
        m_player->m_playerInfo->videoCodecContext=codecContext;
        m_player->m_playerInfo->videoCodec=codec;
    }else if(m_decodeType==AudioDecode){
        if (( m_player->m_playerInfo->formatContext->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && ! m_player->m_playerInfo->formatContext->iformat->read_seek) {
            this->m_audioStartPts =  m_player->m_playerInfo->audioStream->start_time;
            this->m_audioStartPtsTimebase = m_player->m_playerInfo->audioStream->time_base;
        }

        m_player->m_playerInfo->audioCodecContext=codecContext;
        m_player->m_playerInfo->audioCodec=codec;
    }else if(m_decodeType==TextDecode){
        m_player->m_playerInfo->textCodecContext=codecContext;
        m_player->m_playerInfo->textCodec=codec;
    }

    return true;
}

void DecodeThread::closeDecoder()
{
    PlayerInfo* playerInfo=m_player->m_playerInfo;

    if(m_decodeType==VideoDecode){
        if(playerInfo->videoCodecContext){
            avcodec_free_context(&playerInfo->videoCodecContext);
            playerInfo->videoCodecContext=NULL;
        }
        playerInfo->videoCodec=NULL;
    }else if(m_decodeType==AudioDecode){
        if(playerInfo->audioCodecContext){
            avcodec_free_context(&playerInfo->audioCodecContext);
            playerInfo->audioCodecContext=NULL;
        }
        playerInfo->audioCodec=NULL;
    }else if(m_decodeType==TextDecode){
        if(playerInfo->textCodecContext){
            avcodec_free_context(&playerInfo->textCodecContext);
            playerInfo->textCodecContext=NULL;
        }
        playerInfo->textCodec=NULL;
    }

     av_packet_unref(&this->m_pkt);
     m_pktSerial=-1;
     m_hasPendingPacket=false;
     m_audioStartPts=AV_NOPTS_VALUE;
     m_audioNextPts=AV_NOPTS_VALUE;
}

/*
    解码下一帧音频/视频
*/
void DecodeThread::decodeNextAVFrame( AVFrame *frame, bool* valid)
{
    PlayerInfo* playerInfo = m_player->m_playerInfo;
    PlayerConfig* playerConfig = &m_player->m_playerConfig;
    PacketQueue *pktQueue =NULL;
    AVCodecContext* codecCtx=NULL;
    if(m_decodeType==VideoDecode){
        codecCtx=playerInfo->videoCodecContext;
        pktQueue = &playerInfo->videoPacketQueue;
    }else if(m_decodeType==AudioDecode){
        codecCtx=playerInfo->audioCodecContext;
        pktQueue = &playerInfo->audioPacketQueue;
    }

    int ret = AVERROR(EAGAIN);
    *valid=false;
    for (;;) {
        if(m_reqStop){
            return;
        }

        AVPacket pkt;

        if (pktQueue->serial == this->m_pktSerial) {
            do {
                if (pktQueue->abort_request || m_reqStop){
                    return;
                }

                //读取解码后的帧
                ret = avcodec_receive_frame(codecCtx, frame);

                //计算PTS
                if (ret >= 0) {
                    if(m_decodeType==VideoDecode){
                        if (playerConfig->reorderPts) {
                            frame->pts = frame->best_effort_timestamp;
                        }else{
                            frame->pts = frame->pkt_dts;
                        }
                    }else if(m_decodeType==AudioDecode){
                        AVRational tb;
                        tb.num=1;
                        tb.den=frame->sample_rate;
                        if (frame->pts != AV_NOPTS_VALUE)
                            frame->pts = av_rescale_q(frame->pts, av_codec_get_pkt_timebase(codecCtx), tb);
                        else if (this->m_audioNextPts != AV_NOPTS_VALUE)
                            frame->pts = av_rescale_q(this->m_audioNextPts, this->m_audioNextPtsTimebase, tb);
                        if (frame->pts != AV_NOPTS_VALUE) {
                            this->m_audioNextPts = frame->pts + frame->nb_samples;
                            this->m_audioNextPtsTimebase = tb;
                        }
                    }
                }

                if (ret == AVERROR_EOF) {
                    //到达流尾时重置解码器
                    if(m_decodeType==VideoDecode){
                        playerInfo->videoCodecEof=true;
                    }else if(m_decodeType==AudioDecode){
                        playerInfo->audioCodecEof=true;
                    }
                    avcodec_flush_buffers(codecCtx);
                    return ;
                }else if (ret >= 0){
                    *valid=true;
                    return ;
                }
            } while (ret != AVERROR(EAGAIN));
        }

        //从包缓存中取出一包
        do {
            if(m_reqStop){
                return;
            }

            if (pktQueue->nb_packets == 0){
                //通知解复用线程继续解包 TODO
               // SDL_CondSignal(this->empty_queue_cond);
            }
            if (this->m_hasPendingPacket) {
                av_packet_move_ref(&pkt, &this->m_pkt);
                this->m_hasPendingPacket = false;
            } else {
                if (packet_queue_get(pktQueue, &pkt, 1, &this->m_pktSerial) < 0){
                    return;
                }
            }
        } while (pktQueue->serial != this->m_pktSerial);

        //对取出的包进行解码
        if (pkt.data == playerInfo->flushPkt.data) {
            avcodec_flush_buffers(codecCtx);
            if(m_decodeType==VideoDecode){
                playerInfo->videoCodecEof=false;
            }else if(m_decodeType==AudioDecode){
                playerInfo->audioCodecEof=false;

                this->m_audioNextPts = this->m_audioStartPts;
                this->m_audioNextPtsTimebase = this->m_audioStartPtsTimebase;
            }
        } else {
            if (avcodec_send_packet(codecCtx, &pkt) == AVERROR(EAGAIN)) {
                //喂包失败时，将包挂起下个循环再处理
                this->m_hasPendingPacket = true;
                av_packet_move_ref(&this->m_pkt, &pkt);
            }
            av_packet_unref(&pkt);
        }
    }

    if (*valid==true) {
        if(m_decodeType==VideoDecode){
            //计算帧的宽高比
            frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(playerInfo->formatContext, playerInfo->videoStream, frame);

            //将视频向音频或外部时钟同步（对视频帧进行人工丢包）
            double dpts = NAN;
            if (frame->pts != AV_NOPTS_VALUE)
                dpts = av_q2d(playerInfo->videoStream->time_base) * frame->pts;
            if (playerConfig->framedrop) {
                if (frame->pts != AV_NOPTS_VALUE) {
                    double diff = dpts - get_master_clock(playerInfo);
                    if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&
                            diff - playerInfo->frame_last_filter_delay < 0 &&
                            this->m_pktSerial == playerInfo->videoClock.serial &&
                            playerInfo->videoPacketQueue.nb_packets) {
                        playerInfo->frame_drops_early++;
                        av_frame_unref(frame);
                        *valid = false;
                    }
                }
            }
        }
    }

    return;
}

/*
    解码下一帧字幕
*/
void DecodeThread::decodeNextAVText(AVSubtitle *text, bool *valid)
{
    PlayerInfo* playerInfo = m_player->m_playerInfo;
    PacketQueue *pktQueue =&playerInfo->textPacketQueue;
    AVCodecContext* codecCtx=playerInfo->textCodecContext;

    int ret = AVERROR(EAGAIN);
    *valid=false;
    for (;;) {
        if(m_reqStop){
            return;
        }

        AVPacket pkt;

        if (pktQueue->serial == this->m_pktSerial) {
            do {
                if (pktQueue->abort_request || m_reqStop){
                    return;
                }

                if (ret == AVERROR_EOF) {
                    //到达流尾时重置解码器
                    playerInfo->textCodecEof=true;
                    avcodec_flush_buffers(codecCtx);
                    return;
                }else if (ret >= 0){
                    *valid=true;
                    return;
                }
            } while (ret != AVERROR(EAGAIN));
        }

        //从包缓存中取出一包
        do {
            if(m_reqStop){
                return;
            }

            if (pktQueue->nb_packets == 0){
                //通知解复用线程继续解包 TODO
               // SDL_CondSignal(this->empty_queue_cond);
            }
            if (this->m_hasPendingPacket) {
                av_packet_move_ref(&pkt, &this->m_pkt);
                this->m_hasPendingPacket = false;
            } else {
                if (packet_queue_get(pktQueue, &pkt, 1, &this->m_pktSerial) < 0){
                    return;
                }
            }
        } while (pktQueue->serial != this->m_pktSerial);

        //对取出的包进行解码
        if (pkt.data == playerInfo->flushPkt.data) {
            avcodec_flush_buffers(codecCtx);
            playerInfo->textCodecEof=false;
        } else {
            int got_frame = 0;
            ret = avcodec_decode_subtitle2(codecCtx, text, &got_frame, &pkt);
            if (ret < 0) {
                ret = AVERROR(EAGAIN);
            } else {
                if (got_frame && !pkt.data) {
                    this->m_hasPendingPacket = true;
                    av_packet_move_ref(&this->m_pkt, &pkt);
                }
                ret = got_frame ? 0 : (pkt.data ? AVERROR(EAGAIN) : AVERROR_EOF);
            }
            av_packet_unref(&pkt);
        }
    }
}
